package com.bree.erp.entity;

import java.util.Collection;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@NamedQueries({
	@NamedQuery(name=PurchaseOrder.QUERY_ALL_PURCHASEORDER, 
			query="SELECT po FROM PurchaseOrder po"),
	@NamedQuery(name=PurchaseOrder.QUERY_SELECT_PURCHASEORDER, 
			query="SELECT po FROM PurchaseOrder po WHERE po.purchaseRequisition = :purchaseRequisition AND po.supplier = :supplier AND po.status = :status"),
	@NamedQuery(name=PurchaseOrder.QUERY_SELECT_PURCHASEORDER_STATUS, 
			query="SELECT po FROM PurchaseOrder po WHERE po.status = :status"),
	@NamedQuery(name = PurchaseOrder.QUERY_FIND_PURCHASEORDER_PER_PROJSTATUS,
			query = "SELECT p FROM PurchaseOrder p WHERE p.purchaseRequisition.project = :project and p.status = :status"),
	@NamedQuery(name = PurchaseOrder.QUERY_FIND_PURCHASEORDER_PER_USERPROJSTATUS,
			query = "SELECT p FROM PurchaseOrder p WHERE p.owner = :user and p.purchaseRequisition.project = :project and p.status = :status")
})
@Entity
public class PurchaseOrder implements CrudId<Long> {
	
	private static final long serialVersionUID = 1L;

	public static final String QUERY_ALL_PURCHASEORDER = "findAllPurchaseOrder";
	public static final String QUERY_SELECT_PURCHASEORDER = "findPurchaseOrder";
	public static final String QUERY_SELECT_PURCHASEORDER_STATUS = "findPurchaseOrderByStatus";
	public static final String QUERY_FIND_PURCHASEORDER_PER_PROJSTATUS = "findPurchaseOrderssPerProjStatus";
	public static final String QUERY_FIND_PURCHASEORDER_PER_USERPROJSTATUS = "findPurchaseOrdersPerUserProjSatus";

	public static final int COL_INVOICENUMBER_LEN = 25;
	public static final int COL_TERMS_LEN = 20;
	public static final int COL_STATUS_LEN = 20;
	public static final int COL_REMARKS_LEN = 1024;
	public static final int COL_CONFIRMEDBY_LEN = 100;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;
	
	@Temporal(TemporalType.DATE)
	private Date orderDate;
	
	@Temporal(TemporalType.DATE)
	private Date dueDate;
	
	@Temporal(TemporalType.DATE)
	private Date partialDate;
	
	@Temporal(TemporalType.DATE)
	private Date receivedDate;
	
	@OneToOne
	private PrefixSequence poNumber;
	
	@Column(length=COL_REMARKS_LEN)
	private String remarks;
	
	@ManyToOne
	private PurchaseRequisition purchaseRequisition;
	
	@OneToOne
	private Supplier supplier;
	
	@OneToMany(mappedBy="purchaseOrder")
	private Collection<PoItem> items;
	
	@OneToMany(mappedBy="purchaseOrder")
	private Collection<PoAdjustment> adjustments;

	@OneToMany(mappedBy="purchaseOrder", fetch=FetchType.LAZY)
	private Collection<InventoryFlow> inventoryFlows;
		
	@OneToOne
	private Warehouse warehouse;

	@Column(length=COL_INVOICENUMBER_LEN)
	private String invoiceNumber;
	
	@Column(length=COL_TERMS_LEN)
	private String terms;

	@Column(length=COL_STATUS_LEN)
	@Enumerated(EnumType.STRING)
	private Status status;

	@OneToOne
	private User owner;
	
	@Column(length=COL_CONFIRMEDBY_LEN)
	private String confirmedBy;
	
	@OneToOne
	private User createdBy;
	@OneToOne
	private User updatedBy;
	@OneToOne
	private User approvedBy;
	@OneToOne
	private User closedBy;

	@Temporal(TemporalType.TIMESTAMP)
	private Date created;
	@Temporal(TemporalType.TIMESTAMP)
	private Date updated;
	@Temporal(TemporalType.TIMESTAMP)
	private Date approved;
	@Temporal(TemporalType.TIMESTAMP)
	private Date closed;
	
	public void auditCreate(User user) {
		this.setCreatedBy(user);
		this.setCreated(new Date());
		
	}
	
	public void auditUpdate(User user) {
		this.setUpdatedBy(user);
		this.setUpdated(new Date());
		
	}
	
	public double getTotal() {
		
		double sum = 0.0;
		
		if(this.items != null && !this.items.isEmpty()) {
			for(PoItem item : this.items) {
				sum += item.getTotalPrice();
			}
		}
		
		if(this.adjustments != null && !this.adjustments.isEmpty()) {
			for(PoAdjustment adjustment : adjustments) {
				sum += adjustment.getAmount();
			}
		}

		return sum;
		
	}
	
	@Override
	public boolean equals(Object object) {
		
		if(this == object) {
			return true;
		}
		
		if(object instanceof PurchaseOrder) {
			PurchaseOrder that = (PurchaseOrder) object;
			return this.id != null && this.id.equals(that.id);
		}
		
		return false;
	}
	
	@Override
	public int hashCode() {
		return this.id == null ? 0 : this.id.hashCode();
	}
	
	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}
	/**
	 * @return the orderDate
	 */
	public Date getOrderDate() {
		return orderDate;
	}
	/**
	 * @param orderDate the orderDate to set
	 */
	public void setOrderDate(Date orderDate) {
		this.orderDate = orderDate;
	}
	/**
	 * @return the purchaseRequisition
	 */
	public PurchaseRequisition getPurchaseRequisition() {
		return purchaseRequisition;
	}
	/**
	 * @param purchaseRequisition the purchaseRequisition to set
	 */
	public void setPurchaseRequisition(PurchaseRequisition purchaseRequisition) {
		this.purchaseRequisition = purchaseRequisition;
	}
	/**
	 * @return the supplier
	 */
	public Supplier getSupplier() {
		return supplier;
	}
	/**
	 * @param supplier the supplier to set
	 */
	public void setSupplier(Supplier supplier) {
		this.supplier = supplier;
	}
	/**
	 * @return the items
	 */
	public Collection<PoItem> getItems() {
		return items;
	}
	/**
	 * @param items the items to set
	 */
	public void setItems(Collection<PoItem> items) {
		this.items = items;
	}
	/**
	 * @return the status
	 */
	public Status getStatus() {
		return status;
	}
	/**
	 * @param status the status to set
	 */
	public void setStatus(Status status) {
		this.status = status;
	}
	/**
	 * @return the createdBy
	 */
	public User getCreatedBy() {
		return createdBy;
	}
	/**
	 * @param createdBy the createdBy to set
	 */
	public void setCreatedBy(User createdBy) {
		this.createdBy = createdBy;
	}
	/**
	 * @return the updatedBy
	 */
	public User getUpdatedBy() {
		return updatedBy;
	}
	/**
	 * @param updatedBy the updatedBy to set
	 */
	public void setUpdatedBy(User updatedBy) {
		this.updatedBy = updatedBy;
	}
	/**
	 * @return the approvedBy
	 */
	public User getApprovedBy() {
		return approvedBy;
	}
	/**
	 * @param approvedBy the approvedBy to set
	 */
	public void setApprovedBy(User approvedBy) {
		this.approvedBy = approvedBy;
	}
	/**
	 * @return the closedBy
	 */
	public User getClosedBy() {
		return closedBy;
	}
	/**
	 * @param closedBy the closedBy to set
	 */
	public void setClosedBy(User closedBy) {
		this.closedBy = closedBy;
	}
	/**
	 * @return the created
	 */
	public Date getCreated() {
		return created;
	}
	/**
	 * @param created the created to set
	 */
	public void setCreated(Date created) {
		this.created = created;
	}
	/**
	 * @return the updated
	 */
	public Date getUpdated() {
		return updated;
	}
	/**
	 * @param updated the updated to set
	 */
	public void setUpdated(Date updated) {
		this.updated = updated;
	}
	/**
	 * @return the approved
	 */
	public Date getApproved() {
		return approved;
	}
	/**
	 * @param approved the approved to set
	 */
	public void setApproved(Date approved) {
		this.approved = approved;
	}
	/**
	 * @return the closed
	 */
	public Date getClosed() {
		return closed;
	}
	/**
	 * @param closed the closed to set
	 */
	public void setClosed(Date closed) {
		this.closed = closed;
	}
	/**
	 * @return the terms
	 */
	public String getTerms() {
		return terms;
	}

	/**
	 * @param terms the terms to set
	 */
	public void setTerms(String terms) {
		this.terms = terms;
	}

	/**
	 * @return the adjustments
	 */
	public Collection<PoAdjustment> getAdjustments() {
		return adjustments;
	}

	/**
	 * @param adjustments the adjustments to set
	 */
	public void setAdjustments(Collection<PoAdjustment> adjustments) {
		this.adjustments = adjustments;
	}

	/**
	 * @return the warehouse
	 */
	public Warehouse getWarehouse() {
		return warehouse;
	}

	/**
	 * @param warehouse the warehouse to set
	 */
	public void setWarehouse(Warehouse warehouse) {
		this.warehouse = warehouse;
	}

	/**
	 * @return the invoiceNumber
	 */
	public String getInvoiceNumber() {
		return invoiceNumber;
	}

	/**
	 * @param invoiceNumber the invoiceNumber to set
	 */
	public void setInvoiceNumber(String invoiceNumber) {
		this.invoiceNumber = invoiceNumber;
	}

	/**
	 * @return the dueDate
	 */
	public Date getDueDate() {
		return dueDate;
	}

	/**
	 * @param dueDate the dueDate to set
	 */
	public void setDueDate(Date dueDate) {
		this.dueDate = dueDate;
	}

	/**
	 * @return the partialDate
	 */
	public Date getPartialDate() {
		return partialDate;
	}

	/**
	 * @param partialDate the partialDate to set
	 */
	public void setPartialDate(Date partialDate) {
		this.partialDate = partialDate;
	}

	/**
	 * @return the receivedDate
	 */
	public Date getReceivedDate() {
		return receivedDate;
	}

	/**
	 * @param receivedDate the receivedDate to set
	 */
	public void setReceivedDate(Date receivedDate) {
		this.receivedDate = receivedDate;
	}

	/**
	 * @return the poNumber
	 */
	public PrefixSequence getPoNumber() {
		return poNumber;
	}

	/**
	 * @param poNumber the poNumber to set
	 */
	public void setPoNumber(PrefixSequence poNumber) {
		this.poNumber = poNumber;
	}

	/**
	 * @return the inventoryFlows
	 */
	public Collection<InventoryFlow> getInventoryFlows() {
		return inventoryFlows;
	}

	/**
	 * @param inventoryFlows the inventoryFlows to set
	 */
	public void setInventoryFlows(Collection<InventoryFlow> inventoryFlows) {
		this.inventoryFlows = inventoryFlows;
	}

	/**
	 * @return the remarks
	 */
	public String getRemarks() {
		return remarks;
	}

	/**
	 * @param remarks the remarks to set
	 */
	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}

	/**
	 * @return the owner
	 */
	public User getOwner() {
		return owner;
	}

	/**
	 * @param owner the owner to set
	 */
	public void setOwner(User owner) {
		this.owner = owner;
	}

	/**
	 * @return the confirmedBy
	 */
	public String getConfirmedBy() {
		return confirmedBy;
	}

	/**
	 * @param confirmedBy the confirmedBy to set
	 */
	public void setConfirmedBy(String confirmedBy) {
		this.confirmedBy = confirmedBy;
	}
	
}
